package fr.lip6.meta.ple.generation.fh.java;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.emf.common.util.EList;
import org.eclipse.gmt.modisco.java.BodyDeclaration;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.CompilationUnit;
import org.eclipse.gmt.modisco.java.ImportDeclaration;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.java.Model;
import org.eclipse.gmt.modisco.java.NamedElement;
import org.eclipse.gmt.modisco.java.Package;
import org.eclipse.gmt.modisco.java.emf.impl.ConstructorDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.InterfaceDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.MethodDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.PackageImpl;

import artefact.umlClassDiagram.CreateAssociation;
import artefact.umlClassDiagram.CreateClass;
import artefact.umlClassDiagram.CreateGeneralization;
import artefact.umlClassDiagram.CreateInterface;
import artefact.umlClassDiagram.CreateOperation;
import artefact.umlClassDiagram.CreateOperationRefinement;
import artefact.umlClassDiagram.CreatePackage;
import artefact.umlClassDiagram.impl.CreateAttributeImpl;
import fr.lip6.meta.ple.featureIdentification.Feature;
import fr.lip6.meta.ple.generation.strategy.ReadXmiStrategy;
import fr.lip6.meta.ple.generation.tools.PLConstructionFactory;
import fr.lip6.meta.ple.plextraction.config.Configuration;
import fr.lip6.meta.tools.StatementPrimitive;

public class PLConstructionFactoryFHJava extends PLConstructionFactory {
	private String featuresDir;
	static ArrayList<String> allclasss = new ArrayList<String>();
	private ReadXmiStrategy readXmi = null;

	public PLConstructionFactoryFHJava(String featuresDir) {
		this.featuresDir = featuresDir;
	}

	@Override
	public PrintStream createPackage(	StatementPrimitive stPrimitive,
										Feature feat,
										ArrayList<String> classesName	)
					throws FileNotFoundException {
		CreatePackage crPckg = (CreatePackage) stPrimitive.getPrimitive();
		String pckgname = crPckg.getName();
		String pckgpath = crPckg.getLien();
		PackageImpl pckg = GenerateFromXmiFHJava.readpackage(pckgpath, pckgname);
		//Iterator<AbstractTypeDeclaration> declList = pckg.getOwnedElements().iterator();
		PrintStream out = null;

		System.err.println("PLConstructionFactoryFHJava.createPackage(): package name: "+pckg.getName());

		/*while(declList.hasNext()) {
			pckg.getOwnedElements().remove(0);
		}*/

		Iterator<ClassDeclaration> classDecls = GenerateFromXmiFHJava.getClassesDeclaration(feat, crPckg.getName()).iterator();

		while(classDecls.hasNext()) {
			StringBuilder stringBuilder = new StringBuilder();
			ClassDeclaration classDecl = classDecls.next();
			String classPckg = classDecl.getPackage().getName();

			stringBuilder.append(
					classPckg.equals("(default package)")
					? ""
							: "package "+classPckg+";\n");

			// imports //

			String path = crPckg.getLien().split("::")[0];
			Map<String, Model> models = Configuration.getInstance().getModels();
			Model model;
			EList<CompilationUnit> compilUnitList;
			EList<Package> ownedPackages = null;
			CompilationUnit compilUnit = null;
			EList<ImportDeclaration> imports;
			
			if (models == null)
				throw new RuntimeException("Please set up models into configuration.");
			else {
				model = models.get(path);
				compilUnitList = model.getCompilationUnits();
				ownedPackages = model.getOwnedElements();
			}

			for(CompilationUnit cu : compilUnitList) {
				if (cu.getName().equals(classDecl.getName()+".java")) {
					compilUnit = cu;
					break;
				}
			}

			if (compilUnit != null) {
				imports = compilUnit.getImports();

				for(ImportDeclaration importDecl : imports) {
					NamedElement importedElement = importDecl.getImportedElement();

					if (importedElement.isProxy()) {
						// package name construction
						String pckgName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
						stringBuilder.append("import "+pckgName+";\n");
					}
				}
			}

			/*for(String imppackage : GenerateFromXmiFHJava.importedpackage) {
				stringBuilder.append(imppackage+".*;\n");
			}*/

			// class declaration and body //

			stringBuilder.append(((ReadXmiFHJava) readXmi).getClassDeclarationAndBodyText(classDecl, false));

			File dotDir;
			String packagefolders[] = pckgname.split("\\.");
			String packagefoldersText = "";

			if (!pckgname.equals("(default package)"))
				for(int o=0; o<packagefolders.length; o++) {
					packagefoldersText = packagefoldersText+packagefolders[o]+"/";
				}


			if (feat.getId().split("_").length>1) {
				dotDir = new File(featuresDir+"/"+feat.getName()+"/"+packagefoldersText);
			} else {
				dotDir = new File(featuresDir+"/"+feat.getId()+"/"+packagefoldersText); 
			}

			if (!dotDir.exists()) {
				dotDir.mkdirs();
			}

			File dotFile;

			if (feat.getId().split("_").length>1) {
				dotFile = new File(featuresDir+"/"+feat.getName()+"/"+packagefoldersText+"/"+classDecl.getName()+".java");
			}
			else{
				dotFile = new File(featuresDir+"/"+feat.getId()+"/"+packagefoldersText+"/"+classDecl.getName()+".java");
			}

			FileOutputStream fout = new FileOutputStream(dotFile);

			out = new PrintStream(fout);

			out.print(stringBuilder.toString());

			setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

			allclasss.add(classDecl.getName());

			classesName.add(classDecl.getName());
		}

		return out;
	}

	@Override
	public PrintStream createClass(	CreateClass crClass,
									Feature feat,
									ArrayList<String> classesName	)
					throws FileNotFoundException {
		ClassDeclaration  classDecl = GenerateFromXmiFHJava.getClassDeclaration(crClass.getLien(), crClass.getOwener(), crClass.getName());

		Iterator<BodyDeclaration> listatt = classDecl.getBodyDeclarations().iterator();

		while(listatt.hasNext()) {
			classDecl.getBodyDeclarations().remove(0);

		}
		Iterator<FieldDeclarationImpl> fds = GenerateFromXmiFHJava.getFieldsDeclaration(feat, crClass.getOwener(), crClass.getName()).iterator();

		while(fds.hasNext()) {
			FieldDeclarationImpl fd = fds.next();
			classDecl.getBodyDeclarations().add(fd);
		}

		Iterator<ConstructorDeclarationImpl> consDecls = GenerateFromXmiFHJava.getConstructorsDeclaration(feat, crClass.getOwener(), crClass.getName()).iterator();

		while(consDecls.hasNext()) {
			ConstructorDeclarationImpl consDecl = consDecls.next();

			classDecl.getBodyDeclarations().add(consDecl);
		}

		Iterator<MethodDeclaration> ops = GenerateFromXmiFHJava.getOperations(feat, crClass.getOwener(), crClass.getName()).iterator();

		while(ops.hasNext()) {
			MethodDeclarationImpl fd1 = (MethodDeclarationImpl) ops.next();

			classDecl.getBodyDeclarations().add(fd1);

		}

		String packagefolders[] = crClass.getOwener().split("\\.");
		String p2 = "";

		if (!crClass.getOwener().equals("(default package)"))
			for(int o = 0; o<packagefolders.length; o++) {
				p2 = p2+packagefolders[o]+"/";
			}

		File dotDir = new File(featuresDir+"/"+feat.getId()+"/"+ p2);

		if (!dotDir.exists()) {
			dotDir.mkdirs();
		}

		File dotFile = new File(featuresDir+"/"+feat.getId()+"/"+p2+"/"+crClass.getName()+".java");
		FileOutputStream fout = new FileOutputStream(dotFile);
		PrintStream out = new PrintStream(fout);
		StringBuilder stringBuilder = new StringBuilder();
		String classPckg = classDecl.getPackage().getName();

		stringBuilder.append(
				classPckg.equals("(default package)")
				? ""
				: "package "+classPckg+";\n");

		// imports //

		String path = crClass.getLien().split("::")[0];
		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crClass.getName()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String pckgName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+pckgName+";\n");
				}
			}
		}

		/*for(String imppackage: GenerateFromXmiFHJava.importedpackage) {

			stringBuilder.append(imppackage+".*;\n");
		}*/
		
		// class declaration and body //
		
		if (allclasss.contains(classDecl.getName())) {
			stringBuilder.append(((ReadXmiFHJava)readXmi).getClassDeclarationAndBodyText(classDecl, true));
		} else {
			stringBuilder.append(((ReadXmiFHJava)readXmi).getClassDeclarationAndBodyText(classDecl, false));
		}

		out.println(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		classesName.add(classDecl.getName());

		return out;
	}

	@Override
	public PrintStream createGeneralization(	CreateGeneralization crGen,
			Feature feat,
			ArrayList<String> classesName	) throws FileNotFoundException {
		String [] lien = crGen.getLien().split("::");
		String path = lien[0];
		ClassDeclaration  classDecl = GenerateFromXmiFHJava.getClassDeclaration(path, lien[1], crGen.getSub());

		Iterator<BodyDeclaration> listatt = classDecl.getBodyDeclarations().iterator();

		while(listatt.hasNext()) {
			classDecl.getBodyDeclarations().remove(0);
		}

		Iterator<FieldDeclarationImpl> fds = GenerateFromXmiFHJava.getFieldsDeclaration(feat, lien[1], crGen.getSub()).iterator();

		while(fds.hasNext()) {
			FieldDeclarationImpl fd = fds.next();

			classDecl.getBodyDeclarations().add(fd);
		}

		Iterator<ConstructorDeclarationImpl> consDecls = GenerateFromXmiFHJava.getConstructorsDeclaration(feat, lien[1], crGen.getSub()).iterator();

		while(consDecls.hasNext()) {
			ConstructorDeclarationImpl consDecl = consDecls.next();

			classDecl.getBodyDeclarations().add(consDecl);
		}

		Iterator<MethodDeclaration> ops = GenerateFromXmiFHJava.getOperations(feat, lien[1], crGen.getSub()).iterator();

		while(ops.hasNext()) {
			MethodDeclarationImpl methodDecl = (MethodDeclarationImpl) ops.next();

			classDecl.getBodyDeclarations().add(methodDecl);
		}

		Iterator<MethodDeclaration> opref = GenerateFromXmiFHJava.getRefinementoperations(feat, lien[1], crGen.getSub()).iterator();

		while(opref.hasNext()) {
			MethodDeclarationImpl fd1 = (MethodDeclarationImpl) opref.next();

			classDecl.getBodyDeclarations().add(fd1);
		}

		String packagefolders[] = lien[1].split("\\.");
		String p2 = "";

		if (!lien[1].equals("(default package)"))
			for(int o = 0; o<packagefolders.length; o++) {
				p2 = p2+packagefolders[o]+"/";
			}

		File dotDir = new File(featuresDir+"/"+feat.getId()+"/"+ p2);

		if (!dotDir.exists()) {
			dotDir.mkdirs();
		}

		File dotFile = new File(featuresDir+"/"+feat.getId()+"/"+ p2+"/"+crGen.getSub()+".java");
		FileOutputStream fout = new FileOutputStream(dotFile);
		PrintStream out = new PrintStream(fout);
		StringBuilder stringBuilder = new StringBuilder();
		String classPckg = lien[1];

		stringBuilder.append(
				classPckg.equals("(default package)")
				? ""
						: "package "+classPckg+";\n");

		// imports //

		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crGen.getSub()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String pckgName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+pckgName+";\n");
				}
			}
		}

		/*for(String imppackage : GenerateFromXmiFHJava.importedpackage) {
			stringBuilder.append(imppackage+".*;\n");
		}*/

		stringBuilder.append("\n");

		// class declaration and body //

		//if (allclasss.contains(cd.getName()))
		{
			stringBuilder.append(((ReadXmiFHJava) readXmi).getClassDeclarationAndBodyText(classDecl, false));
		}

		allclasss.add(classDecl.getName());

		out.println(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		System.out.println(p2+ " " + feat.getId() + "\n" + stringBuilder.toString());

		classesName.add(crGen.getSub());

		return out;
	}

	@Override
	public PrintStream createAttribute(	CreateAttributeImpl crAttr,
										Feature feat,
										ArrayList<String> classesName	)
					throws FileNotFoundException {
		classesName.add(crAttr.getOwner());
		StringBuilder stringBuilder = new StringBuilder();	
		String lien[] = crAttr.getLien().split("::");
		String path = lien[0];
		String classPckg = lien[1];

		stringBuilder.append(
				classPckg.equals("(default package)")
				? ""
				: "package "+classPckg+";\n");
		
		// imports //

		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crAttr.getOwner()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String pckgName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+pckgName+";\n");
				}
			}
		}

		/*for(String imppackage: GenerateFromXmiFHJava.importedpackage) {
			stringBuilder.append(imppackage+".*;\n");
		}*/
		
		stringBuilder.append("\n");
		
		// class declaration //

		if (allclasss.contains(crAttr.getOwner())) {
			stringBuilder.append("public class "+crAttr.getOwner()+" {\n");
		}
		else {
			stringBuilder.append("public class "+crAttr.getOwner()+" {\n");	
		}

		String packagefolders[] = lien[1].split("\\.");
		String p2 = "";

		if (!lien[1].equals("(default package)"))
			for(int i = 0; i<packagefolders.length; i++) {
				p2 = p2+packagefolders[i]+"/";
			}

		File dotDir;

		if (feat.getId().split("_").length>1) {
			dotDir = new File(featuresDir+"/"+feat.getName()+"/"+p2);
		} else {
			dotDir = new File(featuresDir+"/"+feat.getId()+"/"+ p2);
		}

		if (!dotDir.exists()) {
			dotDir.mkdirs();
		}

		File dotFile = new File(featuresDir+"/"+feat.getId()+"/"+p2+"/"+crAttr.getOwner()+".java");
		FileOutputStream fout = new FileOutputStream(dotFile);


		//FieldDeclarationImpl fd = GenerateFromXmiFHJava.getFieldDeclaration(lien[0], lien[1], crAttr.getOwner(), crAttr.getName());
		Iterator<FieldDeclarationImpl> fds = GenerateFromXmiFHJava.getFieldsDeclaration(feat, lien[1], crAttr.getOwner()).iterator();


		while(fds.hasNext()) {
			FieldDeclarationImpl fld = fds.next();

			stringBuilder.append(readXmi.getFieldDeclarationText(fld)+"\n");
		}

		Iterator<MethodDeclaration> ms = GenerateFromXmiFHJava.getOperations(feat, lien[1], crAttr.getOwner()).iterator();
		while(ms.hasNext()) {
			MethodDeclaration m = ms.next();

			stringBuilder.append(readXmi.getMethodDeclarationAndBodyText(m)+"\n");
		}
		stringBuilder.append("}\n");

		PrintStream out = new PrintStream(fout);
		System.err.println(stringBuilder.toString());
		out.print(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		//out.close();

		return out;
	}

	@Override
	public PrintStream createOperation(	CreateOperation crOp,
										Feature feat,
										ArrayList<String> classesName	)
												throws FileNotFoundException {
		classesName.add(crOp.getOwener());
		StringBuilder stringBuilder = new StringBuilder();
		String lien[] = crOp.getLien().split("::"); // xmi_file::package
		String path = lien[0];
		String pckg = lien[1];

		stringBuilder.append(
				pckg.equals("(default package)")
				? ""
				: "package "+pckg+";\n");
		
		// imports //

		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crOp.getOwener()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String importName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+importName+";\n");
				}
			}
		}

		/*for(String imppackage : GenerateFromXmiFHJava.importedpackage) {
			stringBuilder.append(imppackage+".*;\n");	
		}*/
		
		stringBuilder.append("\n");
		
		// class declaration //

		if (allclasss.contains(crOp.getOwener())) {
			stringBuilder.append("public class "+crOp.getOwener()+" {\n");
		} else {
			stringBuilder.append("public class "+crOp.getOwener()+" {\n");
		}

		String packagefolders[] = lien[1].split("\\.");
		String p2 = "";

		if (!lien[1].equals("(default package)"))
			for(int i = 0; i<packagefolders.length; i++) {
				p2 = p2+packagefolders[i]+"/";
			}

		File dotDir ;

		if (feat.getId().split("_").length>1) {
			dotDir = new File(featuresDir+"/"+feat.getName()+"/"+p2);
		} else {
			dotDir = new File(featuresDir+"/"+feat.getId()+"/"+p2);
		}
		if (!dotDir.exists()) {
			dotDir.mkdirs();
		}
		File dotFile ;
		if (feat.getId().split("_").length>1) {
			dotFile = new File(featuresDir+"/"+feat.getName()+"/"+p2+"/"+crOp.getOwener()+".java");
		}
		else {
			dotFile = new File(featuresDir+"/"+feat.getId()+"/"+p2+"/"+crOp.getOwener()+".java");
		}
		FileOutputStream fout = new FileOutputStream(dotFile);

		//FieldDeclarationImpl fd = GenerateFromXmiFHJava.getFieldDeclaration(lien[0], lien[1], crOp.getOwener(), crOp.getName());
		Iterator<FieldDeclarationImpl> fds = GenerateFromXmiFHJava.getFieldsDeclaration(feat, lien[1], crOp.getOwener()).iterator();
		//System.err.println(" mussab 155 "+o.getName() + "  "+o.getOwener()+ lien[0]+lien[1]);

		while(fds.hasNext()) {
			FieldDeclarationImpl fld = fds.next();

			stringBuilder.append(readXmi.getFieldDeclarationText(fld)+"\n");

		}

		Iterator<ConstructorDeclarationImpl> consDecls = GenerateFromXmiFHJava.getConstructorsDeclaration(feat, lien[1], crOp.getName()).iterator();

		while(consDecls.hasNext()) {
			ConstructorDeclarationImpl consDecl = (ConstructorDeclarationImpl) consDecls.next();

			stringBuilder.append(readXmi.getConstructorDeclarationAndBodyText(consDecl)+"\n");
		}

		Iterator<MethodDeclaration> ms = GenerateFromXmiFHJava.getOperations(feat, lien[1], crOp.getOwener()).iterator();

		while(ms.hasNext()) {
			MethodDeclaration m = ms.next();

			stringBuilder.append(readXmi.getMethodDeclarationAndBodyText(m)+"\n");
		}

		stringBuilder.append("}\n");

		PrintStream out = new PrintStream(fout);
		System.err.println(stringBuilder.toString());
		out.print(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		//out.close();

		return out;
	}

	@Override
	public PrintStream createOperationRefinement(	CreateOperationRefinement crOpRef,
													Feature feat,
													ArrayList<String> classesName	)
															throws FileNotFoundException {
		StringBuilder stringBuilder = new StringBuilder();
		String path = crOpRef.getLien().split("::")[0];

		// imports //

		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crOpRef.getOwner()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String importName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+importName+";\n");
				}
			}
		}
		
		/*for(String imppackage : GenerateFromXmiFHJava.importedpackage) {
			stringBuilder.append(imppackage+".*;\n");	
		}*/
		
		stringBuilder.append("\n");
		
		// class declaration //
		
		if (allclasss.contains(crOpRef.getOwner())) {
			stringBuilder.append("public refines class "+crOpRef.getOwner()+" {\n");
		}
		else {
			stringBuilder.append("public class "+crOpRef.getOwner()+" {\n");	
		}
		
		String [] lien = crOpRef.getLien().split("::");

		File dotDir = new File(featuresDir+"/"+feat.getId()+"/"+ lien[1]);
		if (!dotDir.exists()) {
			dotDir.mkdir();
		}

		File dotFile = new File(featuresDir+"/"+feat.getId()+"/"+lien[1]+"/"+crOpRef.getOwner()+".jak");
		FileOutputStream fout = new FileOutputStream(dotFile);


		//FieldDeclarationImpl fd = GenerateFromXmiFHJava.getFieldDeclaration(lien[0], lien[1], crOpRef.getOwener(), crOpRef.getName());
		Iterator<FieldDeclarationImpl> fds = GenerateFromXmiFHJava.getFieldsDeclaration(feat, lien[1], crOpRef.getOwner()).iterator();
		//System.err.println(" mussab 155 "+o.getName() + "  "+o.getOwener()+ lien[0]+lien[1]);

		while(fds.hasNext()) {
			FieldDeclarationImpl fld = fds.next();

			stringBuilder.append(readXmi.getFieldDeclarationText(fld)+"\n");

		}

		Iterator<ConstructorDeclarationImpl> cons = GenerateFromXmiFHJava.getConstructorsDeclaration(feat, lien[1], crOpRef.getName()).iterator();

		while(cons.hasNext()) {

			ConstructorDeclarationImpl con = (ConstructorDeclarationImpl) cons.next();
			stringBuilder.append(readXmi.getConstructorDeclarationAndBodyText(con)+"\n");


		}

		Iterator<MethodDeclaration> ms = GenerateFromXmiFHJava.getOperations(feat, lien[1], crOpRef.getOwner()).iterator();

		while(ms.hasNext()) {
			MethodDeclaration m = ms.next();

			stringBuilder.append(readXmi.getMethodDeclarationAndBodyText(m)+"\n");
		}

		stringBuilder.append("}\n");

		PrintStream out = new PrintStream(fout);
		System.err.println(stringBuilder.toString());
		out.print(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		//out.close();

		return out;
	}

	public PrintStream createInterface(	CreateInterface crInter,
										Feature feat,
										ArrayList<String> classesName	)
					throws FileNotFoundException {
		InterfaceDeclarationImpl interDecl = GenerateFromXmiFHJava.getInterfaceDeclaration(crInter.getLien(), crInter.getOwner(), crInter.getName());

		Iterator<BodyDeclaration> listatt = interDecl.getBodyDeclarations().iterator();
		while(listatt.hasNext()) {
			interDecl.getBodyDeclarations().remove(0);
		}

		Iterator<MethodDeclaration> ops = GenerateFromXmiFHJava.  getInterFaceoperations(feat, crInter.getOwner(), crInter.getName()).iterator();

		while(ops.hasNext()) {
			MethodDeclarationImpl fd1 = (MethodDeclarationImpl) ops.next();

			if (fd1 != null) {
				interDecl.getBodyDeclarations().add(fd1);
			}
		}

		String packagefolders[] = crInter.getOwner().split("\\.");
		String p2 = "";

		if (!crInter.getOwner().equals("(default package)"))
			for(int o = 0; o<packagefolders.length; o++) {
				p2 = p2+packagefolders[o]+"/";
			}

		File dotDir = new File(featuresDir+"/"+feat.getId()+"/"+p2);

		if (!dotDir.exists()) {
			dotDir.mkdirs();
		}

		File dotFile = new File(featuresDir+"/"+feat.getId()+"/"+p2+"/"+crInter.getName()+".java");
		FileOutputStream fout = new FileOutputStream(dotFile);
		PrintStream out = new PrintStream(fout);
		StringBuilder stringBuilder = new StringBuilder();
		String pckg = interDecl.getPackage().getName();

		stringBuilder.append(
				pckg.equals("(default package)")
				? ""
						: "package "+pckg+";\n");
		
		// imports //

		String path = crInter.getLien().split("::")[0];
		Map<String, Model> models = Configuration.getInstance().getModels();
		Model model;
		EList<CompilationUnit> compilUnitList;
		EList<Package> ownedPackages = null;
		CompilationUnit compilUnit = null;
		EList<ImportDeclaration> imports;
		
		if (models == null)
			throw new RuntimeException("Please set up models into configuration.");
		else {
			model = models.get(path);
			compilUnitList = model.getCompilationUnits();
			ownedPackages = model.getOwnedElements();
		}

		for(CompilationUnit cu : compilUnitList) {
			if (cu.getName().equals(crInter.getName()+".java")) {
				compilUnit = cu;
				break;
			}
		}

		if (compilUnit != null) {
			imports = compilUnit.getImports();

			for(ImportDeclaration importDecl : imports) {
				NamedElement importedElement = importDecl.getImportedElement();

				if (importedElement.isProxy()) {
					// package name construction
					String pckgName = GenerateFromXmiFHJava.getImportName(ownedPackages, importedElement, "");
					stringBuilder.append("import "+pckgName+";\n");
				}
			}
		}

		/*for(String imppackage : GenerateFromXmiFHJava.importedpackage) {
			stringBuilder.append(imppackage+".*;\n");	
		}*/
		
		// interface declaration and body //

		if (allclasss.contains(interDecl.getName())) {
			stringBuilder.append(((ReadXmiFHJava)readXmi).getInterfaceBody(interDecl, true));
		} else {
			stringBuilder.append(((ReadXmiFHJava)readXmi).getInterfaceBody(interDecl, true));
		}

		out.println(stringBuilder.toString());

		setPrintFile(new PrintFile(stringBuilder, dotDir, dotFile, fout, out));

		classesName.add(interDecl.getName());

		return out;
	}

	@Override
	public PrintStream createAssociation(	CreateAssociation crAsso,
			Feature feat,
			ArrayList<String> classesName	)
					throws FileNotFoundException {


		return null;
	}

	public void setReadXmi(ReadXmiStrategy readXmi) {
		this.readXmi = readXmi;
	}
}
